﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

public class Server {
	#region Fields

	private Socket Socket;

	/// <summary>
	/// 端口
	/// </summary>
	private int port;

	/// <summary>
	/// IP地址
	/// </summary>
	private IPAddress address;

	/// <summary>
	/// 监听线程
	/// </summary>
	private Thread listenThread;

	/// <summary>
	/// 是否启动
	/// </summary>
	public bool IsStart = false;


	private Dictionary<string, Client> clientDic = new Dictionary<string, Client>();
	private Dictionary<int, Client> onLineDic = new Dictionary<int, Client>();
	private Dictionary<int, Client> offLineDic = new Dictionary<int, Client>();
	

	#endregion

	private int headLength;


	public Server(string address, int port)
	{
		headLength = ConstantDef.headLength;
		Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

		this.address = IPAddress.Parse(address);
		this.port = port;

		Bind();
	}

	private void Bind()
	{
		EndPoint point = new IPEndPoint(address, port);
		Socket.Bind(point);
	}

	public void StartListen()
	{
		Socket.Listen(1000);
		IsStart = true;

		listenThread = new Thread(ListenClientConnect);
		listenThread.IsBackground = true;
		listenThread.Start(Socket);
	}

	private void ListenClientConnect()
	{
		while (IsStart)
		{
			Socket s = Socket.Accept();
			Client c = new Client(s);
			c.DealMsg += DealMsg;

			AddClient(c);
		}
	}

	private void AddClient(Client client)
	{
		lock (clientDic)
		{
			string key = client.RemoteEndPoint;
			if (!clientDic.ContainsKey(key))
			{
				MyLog.Log("Add : " + key);
				clientDic.Add(key, client);
			}
			else
			{
				clientDic[key] = client;
				MyLog.LogWarning("ClientDic Already Contains : " + key);
			}
		}
	}

	public void RemoveCloseClient()
	{
		foreach (var client in clientDic.Values)
		{
			if (client.IsConnected)
			{
				continue;
			}

			string key = client.RemoteEndPoint;
			if (clientDic.ContainsKey(key)) {
				clientDic.Remove(key);
				Debug.LogError("Remove Client : " + key);
				if (clientDic.Count <= 0)
				{
					break;
				}
			} else {
				MyLog.LogWarning("ClientDic Doesn't Contains : " + key);
			}
		}
	}

	public void Broadcast(SendData data)
	{
		foreach (var client in clientDic.Values)
		{
			client.Send(data);
		}
	}

	private void DealMsg(Client client, RecData data) {
		switch (data.ID) {
			case MethodDef.Login:
				client.UserData = JsonUtility.FromJson<UserData>(data.Content);
				Login(client);
				break;

			case MethodDef.Chat:
				MyLog.LogError("Chat : " + data.Content);

				Chat(data);
				break;
		}
	}

	private void Login(Client client) {
		if (clientDic.ContainsKey(client.RemoteEndPoint)) {
			client.UserData.OnLine = true;
			if (!onLineDic.ContainsKey(client.UserData.ID)) {
				onLineDic.Add(client.UserData.ID, client);
				client.Send(new SendData(MethodDef.LoginCB, JsonUtility.ToJson(new NetCbData(MethodDef.LoginCB)), ReqType.Callback));
			} else {
				MyLog.LogWarning("重复登录");
			}
		} else {
			MyLog.LogWarning(string.Format("User {0} Doesn't Connect !" + client.UserData.ID));
		}
	}

	private void Chat(RecData data)
	{
		ChatData cd = JsonUtility.FromJson<ChatData>(data.Content);
		if (cd.RID.Equals(cd.WID))
		{
			MyLog.LogWarning("Send To Self " + data.Content);
		}

		if (onLineDic.ContainsKey(cd.RID)) {
			Client rClient = onLineDic[cd.RID];

			rClient.Send(new SendData(MethodDef.Chat, data.Content));
		}
		else
		{
			MyLog.LogWarning(cd.RID + " Not OnLine");
		}
	}

	public void CloseSocket()
	{
		if (Socket != null)
		{
			listenThread.Abort(Socket);
			Socket.Close();
		}
	}

	public void Clear()
	{
		IsStart = false;

		foreach (var client in clientDic.Values)
		{
			client.Clear();
		}

		CloseSocket();
	}
}
